import gbk2312 from './gbk2312.js';
const ShpType = {
    SHAPE_UNKNOWN: -1,//Unknow Shape Type (for internal use) 
    SHAPE_NULL: 0,//ESRI Shapefile Null Shape shape type.
    SHAPE_POINT: 1,//ESRI Shapefile Point Shape shape type.
    SHAPE_POLYLINE: 3,//ESRI Shapefile PolyLine Shape shape type.
    SHAPE_POLYGON: 5,//ESRI Shapefile Polygon Shape shape type.
    SHAPE_MULTIPOINT: 8,//ESRI Shapefile Multipoint Shape shape type (currently unsupported).
    SHAPE_POINTZ: 11,//ESRI Shapefile PointZ Shape shape type.
    SHAPE_POLYLINEZ: 13,//ESRI Shapefile PolylineZ Shape shape type(currently unsupported).
    SHAPE_POLYGONZ: 15,//ESRI Shapefile PolygonZ Shape shape type (currently unsupported).
    SHAPE_MULTIPOINTZ: 18,//ESRI Shapefile MultipointZ Shape shape type (currently unsupported).
    SHAPE_POINTM: 21,//ESRI Shapefile PointM Shape shape type
    SHAPE_POLYLINEM: 23,//ESRI Shapefile PolyLineM Shape shape type (currently unsupported).
    SHAPE_POLYGONM: 25,// ESRI Shapefile PolygonM Shape shape type (currently unsupported).
    SHAPE_MULTIPOINTM: 28,//ESRI Shapefile MultiPointM Shape shape type (currently unsupported).
    SHAPE_MULTIPATCH: 31//ESRI Shapefile MultiPatch Shape shape type (currently unsupported).
};
const ShapeFieldType = {
    SHAPE_B: 66,
    SHAPE_C: 67,
    SHAPE_D: 68,
    SHAPE_F: 70,
    SHAPE_G: 71,
    SHAPE_N: 78,
    SHAPE_I: 73,
    SHAPE_L: 76,
    SHAPE_M: 77,
    SHAPE_T: 84,
    SHAPE_P: 80,
    SHAPE_Y: 89
}
const LDID = {
    UTF_16: 79,
    UTF_8: 0,
    ASNI: 77,//for gb2312
}
class samllShape{
    constructor(options) {
        let { shp, dbf } = options
        this.shpFile = shp
        this.shpdataOffset=0;
        this.shpdataLength = 0;
        this.shpdata = [];
        

        this.dbfFile = dbf
        this.dbfdataOffset = 0;
        this.dbfdataLength = 0;
        this.dbfdata = [];

        this.shapeType=0;
        this.shapeTypeString="";
        this.shps=[]
        this.fileds = []
        this.dbfs=[]

        this.dbfcount=0
        this.dbfHeaderbytecount=0
        this.LDID=0;
        
        // this.init()
        this.status=true
        this.error = true

        
    }
    async init () {
        let read_files_result = await this.read_files();
        if (read_files_result[0] == true && read_files_result[1] == true) {
            await this.load();
        }
        return true
    }
    read_files () {
        return Promise.all([this.FileReader_shp(), this.FileReader_dbf()])
    }
    FileReader_shp() {
        return new Promise( (resolve, rejectshp)=> {
            if (this.shpFile != "") {
                let reader = new FileReader();
                reader.onload =  (e)=> {
                    let text = reader.result;
                    if (text.byteLength < 100) {
                        this.status=false
                        this.error = "shp文件不能小于100字节!"
                        resolve(false);
                    }
                    else{
                        this.shpdataLength = text.byteLength;
                        this.shpdata = new DataView(text, 0, text.byteLength);
                        resolve(true)
                    }
                }
                reader.readAsArrayBuffer(this.shpFile);
            }
            else {
                resolve(false)
            }
        })
    }
    FileReader_dbf() {
        return new Promise( (resolve, reject) => {
            if (this.dbfFile != "") {
                let reader = new FileReader();
                reader.onload =  (e)=> {
                    let text = reader.result;
                    if (text.byteLength < 65) {
                        this.status = false
                        this.error = "dbf文件不能小于65字节!"
                        resolve(false);
                    }
                    else {
                        this.dbfdataLength = text.byteLength;
                        this.dbfdata = new DataView(text, 0, text.byteLength);
                        resolve(true)
                    }
                    
                }
                reader.readAsArrayBuffer(this.dbfFile);
            }
            else {
                resolve(false)
            }

        })
    }
    async load () {
        this.Load_shp_Header();
        await this.Load_shp_Records()
        this.Load_dbf_Header()
        await this.Load_dbf_Records()
    }
    reset() {
        this.shpFile = ""
        this.shpdataOffset = 0;
        this.shpdataLength = 0;
        this.shpdata = [];

        this.dbfFile = ""
        this.dbfdataOffset = 0;
        this.dbfdataLength = 0;
        this.dbfdata = [];

        this.dbfcount = 0
        this.dbfHeaderbytecount = 0
        this.LDID = 0;
    }
    Load_shp_Header  () {
        let i_00_03 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        let i_04_07 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        let i_08_11 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        let i_12_15 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        let i_16_19 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        let i_20_23 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        //文件的实际长度
        let i_24_27 = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
        //版本号
        let i_28_31 = this.shpdata.getUint32(this.shpdataOffset, !0); this.shpdataOffset += 4;
        //几何类型
        this.shapeType = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;
        //Xmin
        let d_36_43 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Ymin 
        let d_44_51 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Xmax
        let d_52_59 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Ymax 
        let d_60_67 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Zmin
        let d_68_75 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Zmax 
        let d_76_83 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Mmin
        let d_84_91 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //Mmax
        let d_92_99 = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
        //解析头文件完毕！
        return "";
    }
    Load_shp_Records  () {
        this.shps = [];
        return new Promise( (resolve, reject)=> {
            switch (this.shapeType) {
                case ShpType.SHAPE_POINT:
                    this.shapeTypeString = "point";
                    this.Load_SHAPE_POINT();
                    resolve(true)
                    break;
                case ShpType.SHAPE_POINTZ:
                    // this.shape = new ShpPointZ(src, this.contentLengthBytes);
                    break;
                case ShpType.SHAPE_POLYGON:
                    this.shapeTypeString = "polygon";
                    this.Load_SHAPE_POLYGON();
                    resolve(true)
                    break;
                case ShpType.SHAPE_POLYLINE:
                    this.shapeTypeString = "polyline";
                    this.Load_SHAPE_POLYLINE();
                    resolve(true)
                    break;
                case ShpType.SHAPE_MULTIPATCH:
                case ShpType.SHAPE_MULTIPOINT:
                case ShpType.SHAPE_MULTIPOINTM:
                case ShpType.SHAPE_MULTIPOINTZ:
                case ShpType.SHAPE_POINTM:
                case ShpType.SHAPE_POLYGONM:
                case ShpType.SHAPE_POLYGONZ:
                case ShpType.SHAPE_POLYLINEZ:
                case ShpType.SHAPE_POLYLINEM:
                    reject(this.shapeType + " Shape type is currently unsupported by this library");
                    break;
                default:
                    reject("Encountered unknown shape type (" + this.shapeType + ")");
                    break;
            }
        })
    }
    Load_SHAPE_POINT  () {
        while (this.shpdataOffset < this.shpdataLength) {
            let index = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;//记录号 记录号都是从1开始的,下面1行代码是反转位序
            let leng = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4; //坐标记录长度,是不是为坐标的小数点位数？
            let i_ShapeType = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;//坐标表示的类型
            let x = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;//当前要素的X
            let y = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;//当前要素的Y
            let coordinates = [x, y]
            this.shps.push(coordinates);
        }
    }
    Load_SHAPE_POLYGON  () {
        while (this.shpdataOffset < this.shpdataLength) {
            let coordinates = [[[]]]
            let all_rings = [];
            //记录的头
            let index = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
            let leng = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4; //坐标记录长度,是不是为坐标的小数点位数？
            let i_ShapeType = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let Xmin = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Ymin = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Xmax = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Ymax = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let NumParts = this.shpdata.getUint32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let NumPoints = this.shpdata.getUint32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let Parts = [];
            //Parts数组记录了每个子环的坐标在Points数组中的起始位置
            for (let i = 0; i < NumParts; i++) {
                let offset = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;
                Parts.push(offset);  //每个子环的坐标在Points数组中的起始位置
            }
            //Points数组 记录了所有的坐标信息
            let Points = [];
            for (let i = 0; i < NumPoints; i++) {
                let shppoint = {};
                shppoint.x = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
                shppoint.y = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
                Points.push(shppoint);
            }
            let rings = [];
            for (let j = 0; j < NumParts; j++) {
                let i_start = Parts[j];
                let one_polygon = [];
                let i_end = 0;
                if (j + 1 < NumParts) {
                    i_end = Parts[j + 1];
                }
                else {
                    i_end = Points.length;
                }
                for (let i = i_start; i < i_end; i++) {
                    let shppoint = Points[i];
                    let one_polygon_one_point = [];
                    one_polygon_one_point.push(shppoint.x); one_polygon_one_point.push(shppoint.y);
                    one_polygon.push(one_polygon_one_point);
                }
                //因为shp文件存储的坐标点 在一个面上 第一个点和最后一个点相同 arcgis api 不能重复
                // one_polygon.pop(one_polygon.length - 1);
                rings.push(one_polygon);
            }
            this.shps.push(rings);
        }
    }
    Load_SHAPE_POLYLINE  () {
        while (this.shpdataOffset < this.shpdataLength) {
            //记录的头
            let index = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4;
            let leng = this.shpdata.getUint32(this.shpdataOffset, !1); this.shpdataOffset += 4; //坐标记录长度,是不是为坐标的小数点位数？
            let i_ShapeType = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let Xmin = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Ymin = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Xmax = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let Ymax = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
            let NumParts = this.shpdata.getUint32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let NumPoints = this.shpdata.getUint32(this.shpdataOffset, !0); this.shpdataOffset += 4;
            let Parts = [];
            //Parts数组记录了每个子环的坐标在Points数组中的起始位置
            for (let i = 0; i < NumParts; i++) {
                let offset = this.shpdata.getInt32(this.shpdataOffset, !0); this.shpdataOffset += 4;
                Parts.push(offset);  //每个子环的坐标在Points数组中的起始位置
            }
            //Points数组 记录了所有的坐标信息
            let Points = [];
            for (let i = 0; i < NumPoints; i++) {
                let shppoint = {};
                shppoint.x = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
                shppoint.y = this.shpdata.getFloat64(this.shpdataOffset, !0); this.shpdataOffset += 8;
                Points.push(shppoint);
            }
            let rings = [];
            for (let j = 0; j < NumParts; j++) {
                let i_start = Parts[j];
                let one_polygon = [];
                let i_end = 0;
                i_end = (j + 1 < NumParts) ? Parts[j + 1] : i_end = Points.length;

                for (let i = i_start; i < i_end; i++) {
                    let shppoint = Points[i];
                    let one_polygon_one_point = [];
                    //如果存在的是平面坐标需要修改成为经纬度坐标  以后改
                    one_polygon_one_point.push(shppoint.x); one_polygon_one_point.push(shppoint.y);
                    one_polygon.push(one_polygon_one_point);
                }
                rings.push(one_polygon);
            }
            this.shps.push(rings);
        }
    }
    ByteToStr (utf8Bytes) {
        switch (this.LDID) {
            case LDID.UTF_16:
                break;
            case LDID.UTF_8:
                break;
            case LDID.ASNI:
                let gggg = gbk2312.decode(utf8Bytes);
                return gggg
            default:
                throw (new Error("Encountered unknown  Language driver ID (" + this.LDID + ")"));
        }
        let unicodeStr = "";
        for (let pos = 0; pos < utf8Bytes.length;) {
            let flag = utf8Bytes[pos];
            let unicode = 0;
            if ((flag >>> 7) === 0) {
                unicodeStr += String.fromCharCode(utf8Bytes[pos]);
                pos += 1;

            } else if ((flag & 0xFC) === 0xFC) {
                unicode = (utf8Bytes[pos] & 0x3) << 30;
                unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24;
                unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18;
                unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12;
                unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6;
                unicode |= (utf8Bytes[pos + 5] & 0x3F);
                unicodeStr += String.fromCharCode(unicode);
                pos += 6;

            } else if ((flag & 0xF8) === 0xF8) {
                unicode = (utf8Bytes[pos] & 0x7) << 24;
                unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18;
                unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12;
                unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6;
                unicode |= (utf8Bytes[pos + 4] & 0x3F);
                unicodeStr += String.fromCharCode(unicode);
                pos += 5;

            } else if ((flag & 0xF0) === 0xF0) {
                unicode = (utf8Bytes[pos] & 0xF) << 18;
                unicode |= (utf8Bytes[pos + 1] & 0x3F) << 12;
                unicode |= (utf8Bytes[pos + 2] & 0x3F) << 6;
                unicode |= (utf8Bytes[pos + 3] & 0x3F);
                unicodeStr += String.fromCharCode(unicode);
                pos += 4;

            } else if ((flag & 0xE0) === 0xE0) {
                unicode = (utf8Bytes[pos] & 0x1F) << 12;;
                unicode |= (utf8Bytes[pos + 1] & 0x3F) << 6;
                unicode |= (utf8Bytes[pos + 2] & 0x3F);
                unicodeStr += String.fromCharCode(unicode);
                pos += 3;

            } else if ((flag & 0xC0) === 0xC0) { //110
                unicode = (utf8Bytes[pos] & 0x3F) << 6;
                unicode |= (utf8Bytes[pos + 1] & 0x3F);
                unicodeStr += String.fromCharCode(unicode);
                pos += 2;

            } else {
                unicodeStr += "?";
                pos += 1;
            }
        }
        return unicodeStr;
    }
    Load_dbf_Header  () {
        //读取dbf头文件 不定长字节
        let i_0 = this.dbfdata.getInt8(this.dbfdataOffset, !0); this.dbfdataOffset += 1;//表示当前的版本信息
        this.dbfdataOffset += 3;//表示最近的更新日期，按照YYMMDD格式。
        this.dbfcount = this.dbfdata.getUint32(this.dbfdataOffset, !0); this.dbfdataOffset += 4; //记录条数
        this.dbfHeaderbytecount = this.dbfdata.getUint16(this.dbfdataOffset, !0); this.dbfdataOffset += 2;//文件头中的字节数
        let i_10_11 = this.dbfdata.getUint16(this.dbfdataOffset, !0); this.dbfdataOffset += 2; //一条记录中的字节长度
        this.dbfdataOffset += 2;//2个字节	保留字节，用于以后添加新的说明性信息时使用，这里用0来填写。
        this.dbfdataOffset += 1;//表示未完成的操作。
        this.dbfdataOffset += 1;//dBASE IV编密码标记。
        this.dbfdataOffset += 12;//保留字节，用于多用户处理时使用
        this.dbfdataOffset += 1;//DBF文件的MDX标识。在创建一个DBF 表时 ，如果使用了MDX 格式的索引文件，那么 DBF 表的表头中的这个字节就自动被设置了一个标志，当你下次试图重新打开这个DBF表的时候，数据引擎会自动识别这个标志，如果此标志为真，则数据引擎将试图打开相应的MDX 文件
        this.LDID = this.dbfdata.getInt8(this.dbfdataOffset, !0);//Language driver ID. 29  编码字节
        this.dbfdataOffset += 1;
        this.dbfdataOffset += 2;//保留字节，用于以后添加新的说明性信息时使用，这里用0来填写。
        let d_sxnum = (this.dbfHeaderbytecount - 1 - 32) / 32;//计算出属性列的个数
        let fileds = [];
        for (let i = 0; i < d_sxnum; i++) {
            let filed = {};
            let namebyte = new Uint8Array(this.dbfdata.buffer, this.dbfdataOffset, 11); this.dbfdataOffset += 11;//记录项名称，是ASCII码值。
            let valuebyte = [];
            namebyte.forEach(function (value) { if (value != 32 && value != 0) { valuebyte.push(value); } })
            filed.name = this.ByteToStr(valuebyte);
            filed.type = new Uint8Array(this.dbfdata.buffer, this.dbfdataOffset, 1)[0]; this.dbfdataOffset += 1;//记录项的数据类型，是ASCII码值(B、C、D、G、L、M和N) 列的字段类型
            this.dbfdataOffset += 4;//保留字节，用于以后添加新的说明性信息时使用，这里用0来填写
            let lengthU = new Uint8Array(this.dbfdata.buffer, this.dbfdataOffset, 1); this.dbfdataOffset += 1;//记录项长度，二进制型
            filed.Length = lengthU[0];

            this.dbfdataOffset += 1;//记录项的精度，二进制型
            this.dbfdataOffset += 2;//保留字节，用于以后添加新的说明性信息时使用，这里用0来填写
            this.dbfdataOffset += 1;//工作区ID
            this.dbfdataOffset += 10;//保留字节，用于以后添加新的说明性信息时使用，这里用0来填写
            this.dbfdataOffset += 1;//MDX标识。如果存在一个MDX 格式的索引文件，那么这个记录项为真，否则为空
            fileds.push(filed);
        }
        fileds.push({
            name:"fid",
            type:"objectid",
        })
        this.fileds = fileds;
        this.dbfdataOffset += 1;//记录项终止标识
    }
    Load_dbf_Records  () {
        this.dbfs = [];
        return new Promise( (resolve, reject) =>{
            let values = [];
            for (let i = 0; i < this.dbfcount; i++) {
                this.dbfdataOffset += 1;//第一个字节是删除标志，若记录被删除，则该字节为0x2A即"*"；否则为0x20即空格
                let onevalue = {};
                for (let j = 0; j < this.fileds.length; j++) {
                    let name = this.fileds[j].name;
                    if(name=="fid"){
                        continue;
                    }
                    let length = this.fileds[j].Length;
                    let type = this.fileds[j].type;
                    let valuebyte2 = new Uint8Array(this.dbfdata.buffer, this.dbfdataOffset, length);//记录项值。
                    this.dbfdataOffset += length;
                    let valuebyte = [];
                    valuebyte2.forEach(function (value, index) { if (value != 32 && value != 0) { valuebyte.push(value); } })
                    let value = this.dbf_field_convert(valuebyte, type);
                    onevalue[name] = value;
                }
                onevalue.fid=`${i+1}`;
                values.push(onevalue)
            }
            this.dbfs = values;
            resolve(true)
        });

    }
    dbf_field_convert  (valuebyte, fieldtype) {
        switch (fieldtype) {
            case ShapeFieldType.SHAPE_B: //Double 。
                return new Number(String.fromCharCode.apply(null, valuebyte)).valueOf();
            case ShapeFieldType.SHAPE_C: //字符型	各种字符。
                return this.ByteToStr(valuebyte);
            case ShapeFieldType.SHAPE_D: // 日期型	用于区分年、月、日的数字和一个字符，内部存储按照YYYYMMDD格式。
                return this.ByteToStr(valuebyte);
            case ShapeFieldType.SHAPE_F: // Float
                return new Number(String.fromCharCode.apply(null, valuebyte)).valueOf();
            case ShapeFieldType.SHAPE_G: // (General or OLE)	各种字符。
                return String.fromCharCode.apply(null, valuebyte)
            case ShapeFieldType.SHAPE_N: // 数值型(Numeric)	- . 0 1 2 3 4 5 6 7 8 9 
                return new Number(String.fromCharCode.apply(null, valuebyte)).valueOf();
            case ShapeFieldType.SHAPE_I: // Integer
                return new Number(String.fromCharCode.apply(null, valuebyte)).valueOf();
            case ShapeFieldType.SHAPE_L: // 逻辑型（Logical）	? Y y N n T t F f (? 表示没有初始
                break;
            case ShapeFieldType.SHAPE_M: // (Memo)	各种字符。
                break;
            case ShapeFieldType.SHAPE_T: //  DateTime
                break;
            case ShapeFieldType.SHAPE_P: // Picture
                break;
            case ShapeFieldType.SHAPE_Y: //货币
                break;
            default:
                throw (new ShpError(this.shapeType + " Shape type is currently unsupported by this library"));
        }
    }

}
export function samllShape_set() {
    global["vapp"].config.globalProperties.$samllShape = samllShape
}